package com.kitty.game.rank.service.handler;

import com.kitty.common.utils.SpringUtils;
import com.kitty.game.rank.model.record.RankRecord;
import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;

/**分组，组内分段排行榜*/
public abstract class GroupRangeRankHandler {
    /**
     * 用于快速查找 id --> record
     */
    private ConcurrentMap<Serializable, ConcurrentMap<Serializable, ConcurrentMap<Serializable, RankRecord>>> cache = new ConcurrentHashMap<>();

    private ConcurrentMap<Serializable, ConcurrentMap<Serializable, ConcurrentSkipListMap<RankRecord, Serializable>>> ranks = new ConcurrentHashMap<>();

    @Getter
    @Setter
    private int rankSize = 100;
    /**
     * 缓存数量要比排行榜数量大，防止战力下降，没有数据补充
     */
    @Getter
    private int cacheSize = rankSize + 50;

    /**
     * 读取数据库进行初始化
     */
    protected abstract void  init();

    protected boolean put(Serializable group, Serializable range, Serializable key, RankRecord data) {
        ConcurrentMap<Serializable, ConcurrentMap<Serializable, RankRecord>> cacheMapByGroup = cache.get(group);
        if (cacheMapByGroup == null) {
            cacheMapByGroup = cache.putIfAbsent(group, new ConcurrentHashMap<>());
            if (cacheMapByGroup == null) {
                cacheMapByGroup = cache.get(group);
            }
        }
        ConcurrentMap<Serializable, RankRecord> cacheMapByRange = cacheMapByGroup.get(range);
        if (cacheMapByRange == null) {
            cacheMapByRange = cacheMapByGroup.putIfAbsent(range, new ConcurrentHashMap());
            if (cacheMapByRange == null) {
                cacheMapByRange = cacheMapByGroup.get(range);
            }
        }
        cacheMapByRange.put(key, data);


        ConcurrentMap<Serializable, ConcurrentSkipListMap<RankRecord, Serializable>> mapByGroup = ranks.get(group);
        if (mapByGroup == null) {
            mapByGroup = ranks.putIfAbsent(group, new ConcurrentHashMap<>());
            if (mapByGroup == null) {
                mapByGroup = ranks.get(group);
            }
        }
        ConcurrentSkipListMap<RankRecord, Serializable> mapByRange = mapByGroup.get(range);
        if (mapByRange == null) {
            mapByRange = mapByGroup.putIfAbsent(range, new ConcurrentSkipListMap<>());
            if (mapByRange == null) {
                mapByRange = mapByGroup.get(range);
            }
        }

        mapByRange.put(data, key);
        if (mapByRange.size() > cacheSize) {
            Map.Entry<RankRecord, Serializable> lastEntry = mapByRange.pollLastEntry();
            remove(group, range, lastEntry.getValue());

            if (lastEntry.getValue() != key) {
                SpringUtils.getRankService().removeRandView(String.valueOf(lastEntry.getValue()));
                return true;
            }

            return false;
        }
        return true;
    }

    protected RankRecord remove(Serializable group, Serializable range, Serializable key) {
        ConcurrentMap<Serializable, ConcurrentMap<Serializable, RankRecord>> cacheMapByGroup = cache.get(group);
        if (cacheMapByGroup == null) {
            return null;
        }
        ConcurrentMap<Serializable, RankRecord> cacheMapByRange = cacheMapByGroup.get(range);
        if (cacheMapByRange == null) {
            return null;
        }

        RankRecord value = cacheMapByRange.remove(key);
        if (value == null) {
            return null;
        }

        ConcurrentMap<Serializable, ConcurrentSkipListMap<RankRecord, Serializable>> rankMapByGroup = ranks.get(group);
        if (rankMapByGroup == null) {
            return null;
        }

        ConcurrentSkipListMap<RankRecord, Serializable> rankMapByRange = rankMapByGroup.get(range);
        if (rankMapByRange == null) {
            return null;
        }

        Serializable removeKey = rankMapByRange.remove(value);
        if (removeKey != null) {
            return value;
        }

        return null;
    }

    /**
     * 由外部接受事件进行数据更新
     * @param key
     * @param data
     */
    public boolean update(Serializable group, Serializable range, Serializable key, RankRecord data) {
        remove(group, range, key);
        return put(group, range, key, data);
    }

    public List<RankRecord> getRecordsFrom(Serializable group, Serializable range, int start, int end) {
        List<RankRecord> result = new ArrayList<>();

        int i =0;
        ConcurrentMap<Serializable, ConcurrentSkipListMap<RankRecord, Serializable>> mapByGroup = ranks.get(group);
        if (mapByGroup != null) {
            ConcurrentSkipListMap<RankRecord, Serializable> mapByRange = mapByGroup.get(range);
            if (mapByRange != null) {
                for (Iterator<Map.Entry<RankRecord, Serializable>> it = mapByRange.entrySet().iterator(); it.hasNext();) {
                    Map.Entry<RankRecord, Serializable> next = it.next();
                    if (i++ < end) {
                        result.add(next.getKey());
                    }
                }
            }
        }

        return result;
    }
}
